﻿using System;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;


namespace HttpClientStudy.Core.Utilities
{
    /// <summary>
    /// 应用工具类
    /// </summary>
    public class AppUtility
    {
        /// <summary>
        /// 获取应用运行时各种路径
        /// </summary>
        /// <returns></returns>
        public static IDictionary<string, (string desc, string? path)> GetApplicationPaths()
        {
            var pathDic = new Dictionary<string, (string desc, string? path)>()
            {
                //当前运行的exe的完整路径，包含exe文件名，只用于WinForm
                {"Application.ExecutablePath",("程序集基完整路径(仅WinForm)", "Application.ExecutablePath 只适用于WinForm") },

                //程序的启动路径：只用于WinForm
                {"Application.StartupPath",("程序集启动路径(仅WinForm)", "Application.StartupPath 只适用于WinForm") },

                //当前执行的exe或启动项目的路径，通过AppContext
                {"AppContext.BaseDirectory",("执行或启动路径",AppContext.BaseDirectory) },  

                //当前执行的exe的目录，不包含exe名，使用AppDomain
                {"AppDomain.CurrentDomain.BaseDirectory",("程序集解析程序用于探测程序集的基目录",AppDomain.CurrentDomain.BaseDirectory) }, 

                //程序安装或启动基目录  包含应用程序的目录的名称
                {"AppDomain.CurrentDomain.SetupInformation.ApplicationBase",("程序安装或启动基目录",AppDomain.CurrentDomain.SetupInformation.ApplicationBase) }, 

                //当前进程的主模块路径，包含exe名
                {"Process.GetCurrentProcess().MainModule.FileName",("当前进程的主模块路径",Process.GetCurrentProcess()?.MainModule?.FileName) }, 

                //环境变量：用户当前工作目录的完整限定路径
                {"Environment.CurrentDirectory",("用户当前工作目录的完整限定路径",Environment.CurrentDirectory) }, 

                //环境变量：当前exe的完整路径，包含exe名，通过命令行参数
                {"Environment.GetCommandLineArgs()[0]",("当前exe的完整路径",Environment.GetCommandLineArgs()[0]) }, 

                //当前工作目录的路径（可变）
                {"Directory.GetCurrentDirectory",("当前工作目录的路径（可变）",Directory.GetCurrentDirectory()) },
                
                //当前Assembly的加载路径，包含dll或exe名
                {"Assembly.GetExecutingAssembly().Location",("当前Assembly的加载路径",Assembly.GetExecutingAssembly().Location) },

                //入口程序集的路径
                {"Assembly.GetEntryAssembly().Location",("入口程序集的路径",Assembly.GetEntryAssembly()?.Location) },

                //已过时：当前程序集的CodeBase路径，可能为file URI格式
                //{"Assembly.GetExecutingAssembly().CodeBase",("当前程序集的CodeBase路径",Assembly.GetExecutingAssembly()?.CodeBase) },

                //已过时：入口程序集的CodeBase路径，可能为file URI格式
                //{"Assembly.GetEntryAssembly().CodeBase",("入口程序集的CodeBase路径",Assembly.GetEntryAssembly()?.CodeBase) },
            };

            return pathDic;
        }

        /// <summary>
        /// 启动webapi项目
        /// (出现webapi项目启动命令行窗口)
        /// </summary>
        public static void StartWebApiProject()
        {
            string projectAndMutexName = WebApiConfigManager.GetWebApiConfigOption().CurrentValue.WebAppMutexName;

            //webapi项目不在运行状态则启动webapi项目
            if (WebAppIsRunningByMutex(projectAndMutexName) == false)
            {
                //VS项目根目录
                string vsProjectPath = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory)!.Parent!.Parent!.Parent!.Parent!.FullName;

                //webapi项目根项目
                string webApiProjectPath = Path.Combine(vsProjectPath, projectAndMutexName);

                //启动命令信息
                var prossInfo = new System.Diagnostics.ProcessStartInfo("dotnet", $"run --project {webApiProjectPath}")
                {
                    UseShellExecute = true,
                    CreateNoWindow = false,
                    RedirectStandardOutput = false
                };

                //启动
                Process.Start(prossInfo);
            }
        }

        /// <summary>
        /// 关闭webapi项目
        /// </summary>
        public static void ExitWebApiProject()
        {
            string projectAndMutexName = WebApiConfigManager.GetWebApiConfigOption().CurrentValue.WebAppMutexName;

            //webapi为运行状态则关闭
            if (WebAppIsRunningByMutex(projectAndMutexName))
            {
                var webApiProcess = System.Diagnostics.Process.GetProcessesByName(projectAndMutexName);

                if (webApiProcess != null && webApiProcess.Length > 0)
                {
                    webApiProcess[0].Kill();
                }
            }

        }

        /// <summary>
        /// 新窗口运行WebApi发布程序
        /// </summary>
        /// <param name="exeFile">WebApi程序文件</param>
        /// <param name="args">WebApi启动参数</param>
        /// <param name="stayWindow">是否保持命令窗口(不关闭)</param>
        /// <returns></returns>
        public static string RunWebApiExeFile(string exeFile, bool stayWindow = false, params string[] args)
        {
            string executedMessage = string.Empty;
            try
            {
                if (!Path.IsPathRooted(exeFile))
                {
                    exeFile = Path.GetFullPath(exeFile, Environment.CurrentDirectory);
                }

                if (!File.Exists(exeFile))
                {
                    executedMessage = $"可执行文件[{exeFile}]不存在";
                    return executedMessage;
                }

                //纯文件名(不带扩展名)作用 新窗口标题
                string fileName = Path.GetFileNameWithoutExtension(exeFile);


                //不同操作系统，需要不同的启动命令
                string systemShell = "cmd.exe";

                string cmdArgsText = string.Empty;

                //保持新命令窗口(不自动关闭)
                if (stayWindow)
                {
                    cmdArgsText = $"/c start \"{fileName}\" cmd /k \"\"\"{exeFile}\" {string.Join(" ",args)}";
                }
                else
                { 
                    cmdArgsText = $"/c start \"{fileName}\" \"\"\"{exeFile}\" {string.Join(" ",args)}";
                }

                ProcessStartInfo startInfo = new ProcessStartInfo()
                {
                    FileName = systemShell,
                    Arguments = cmdArgsText,

                    //执行命令的线程本身不弹出新窗口
                    //确保弹出新窗口：是使用cmd start 实现
                    //保持新窗口不关闭：使用 start cmd /k 实现
                    UseShellExecute = false,

                    //true时不创建新窗口，false才是创建新窗口
                    CreateNoWindow = false,
                };

                //启动进程
                using (Process process = new Process() { StartInfo = startInfo })
                {
                    process.Start();
                }

                executedMessage = $"程序[{exeFile}]已在新的命令行窗口执行。如果未出现新命令行窗口，可能是程序错误造成窗口闪现！";
            }
            catch (Exception ex)
            {
                executedMessage = $"启动程序[{exeFile}]出现异常：[{ex.Message}]";
            }
            finally
            {

            }

            return executedMessage;
        }

        /// <summary>
        /// 强制停止WebApi程序
        /// </summary>
        /// <returns></returns>
        public static string StopWebApiExeFile()
        {
            string executedMessage = string.Empty;

            string projectAndMutexName = WebApiConfigManager.GetWebApiConfigOption().CurrentValue.WebAppMutexName;
            try
            {
                if (WebAppIsRunningByProcessName(projectAndMutexName))
                {
                    var webApiProcess = Process.GetProcessesByName(projectAndMutexName)?.FirstOrDefault();
                    webApiProcess?.Kill();

                    executedMessage = $"WebApi程序[进程号：{webApiProcess?.Id}，进程名：{webApiProcess?.ProcessName}]，已关闭！";
                }
                else
                {
                    executedMessage = $"WebApi程序,未在运行！";
                }
            }
            catch (Exception ex)
            {
                executedMessage = $"强制停止WebApi程序时，异常：{ex.Message}";
            }

            return executedMessage;
        }

        /// <summary>
        /// 执行CMD命令
        /// </summary>
        /// <param name="command">CMD命令</param>
        /// <param name="args">命令参数</param>
        /// <returns></returns>
        public static string RunCmd(string command, params string[] args)
        {
            string executedMessage = string.Empty;
            try
            {
                ProcessStartInfo startInfo = new ProcessStartInfo()
                {
                    FileName = "cmd",

                    Arguments = $"/c {command} {string.Join(" ",args)}",

                    // 重定向标准输出
                    RedirectStandardOutput = true, 

                    // 不使用系统外壳程序启动
                    UseShellExecute = false, 

                    // 不创建新窗口
                    CreateNoWindow = true 
                };

                // 启动进程
                using (Process? process = Process.Start(startInfo))
                {
                    // 读取cmd的输出
                    using (StreamReader? reader = process?.StandardOutput)
                    {
                        executedMessage = reader?.ReadToEnd() ?? "";
                    }
                }
            }
            catch (Exception ex)
            {
                executedMessage = $"执行命令[{command}]出现异常：[{ex.Message}]";
            }
            finally
            {

            }

            return executedMessage;
        }

        /// <summary>
        /// 互斥锁是否存在
        /// </summary>
        /// <param name="mutexName">互斥锁名称</param>
        /// <returns>是否存在</returns>
        private static bool WebAppIsRunningByMutex(string mutexName)
        {
            bool createdResult = true;

            //创建互斥锁
            using (var mutex = new Mutex(true, mutexName, out createdResult))
            {
                if (createdResult)
                {
                    mutex.ReleaseMutex();
                }
            }

            //互斥锁是否创建成功
            return !createdResult;
        }

        /// <summary>
        /// 进程是否存在
        /// </summary>
        /// <param name="processName">进程名</param>
        /// <returns>是否存在</returns>
        private static bool WebAppIsRunningByProcessName(string processName)
        {
            bool processExists = Process.GetProcessesByName(processName).ToList().Count == 0;

            return processExists;
        }

    }
}
